package simpledb;

import java.util.HashMap;
import java.util.Map;


/**
 * Knows how to compute some aggregate over a set of IntFields.
 */
public class IntAggregator implements Aggregator {

    int gbfield ;
    Type gbfieldtype ;
    int afield ;
    Op what ;


    /**
     * Aggregate constructor
     * @param gbfield the 0-based index of the group-by field in the tuple, or NO_GROUPING if there is no grouping
     * @param gbfieldtype the type of the group by field (e.g., Type.INT_TYPE), or null if there is no grouping
     * @param afield the 0-based index of the aggregate field in the tuple
     * @param what the aggregation operator
     */
    public IntAggregator( int gbfield, Type gbfieldtype, int afield, Op what ) {
        // some code goes here
        this.gbfield = gbfield ;
        this.gbfieldtype =  gbfieldtype ;
        this.afield = afield ;
        this.what = what ;
    }


    Map<Integer , Integer >  aggrResultMap = new HashMap();
    Map<Integer , AvgTempVariable >  avgTempMap = new HashMap();

    TupleDesc tupleDesc  = null ;


//    select sum(afield)  from table   group by  gbfield

    /**
     * Merge a new tuple into the aggregate, grouping as indicated in the constructor
     * @param tup the Tuple containing an aggregate field and a group-by field
     */
    public void merge(Tuple tup) {
        // some code goes here

        if( tupleDesc == null ) {
            tupleDesc = tup.getTupleDesc() ;
        }

        int gbFieldId  ;

        if( gbfield != -1) {
            IntField gbField = (IntField)tup.getField( gbfield );
            gbFieldId  = gbField.getValue() ;
        }else{
            gbFieldId = -1 ;
        }

        Integer gbFieldValue = aggrResultMap.get( gbFieldId ) ;

//        if( this.gbfieldtype.equals(gbField.getType()) ){

            IntField intField = (IntField)tup.getField( afield );
            int newFieldValue = intField.getValue();

            AvgTempVariable avgTempVariable  = null ;

            if( what.equals(Op.AVG) ) {
                avgTempVariable  = avgTempMap.get(gbFieldId);
                if(  avgTempVariable == null ){
                    avgTempVariable = new AvgTempVariable( newFieldValue  , 1);
                }else{
                    avgTempVariable.setFieldValue( newFieldValue + avgTempVariable.getFieldValue() );
                    avgTempVariable.setTimes( avgTempVariable.getTimes()+1 );
                }
            }

            if( gbFieldValue ==  null ) {
//                第一次找到相关记录

                if( what.equals(Op.AVG) ) {
                    aggrResultMap.put( gbFieldId , newFieldValue );
                    avgTempMap.put( gbFieldId , avgTempVariable );

                }else if( what.equals(Op.COUNT) ) {
                    aggrResultMap.put( gbFieldId , 1 );
                } else {
                    aggrResultMap.put( gbFieldId , newFieldValue );
                }

            }else{
//               group有多条记录
                if( what.equals(Op.SUM) ) {

                    aggrResultMap.put( gbFieldId , newFieldValue + gbFieldValue );
                }else if( what.equals(Op.MIN) ){

                    if( newFieldValue < gbFieldValue ) {
                        aggrResultMap.put( gbFieldId , newFieldValue );
                    }else{
                        aggrResultMap.put( gbFieldId , gbFieldValue );
                    }
                }else if( what.equals(Op.MAX) ){

                    if( newFieldValue > gbFieldValue ) {
                        aggrResultMap.put( gbFieldId , newFieldValue );
                    }else{
                        aggrResultMap.put( gbFieldId , gbFieldValue );
                    }

                }else if( what.equals(Op.COUNT ) ){

                    aggrResultMap.put( gbFieldId , gbFieldValue + 1 );

                }else if( what.equals(Op.AVG) ){

                    avgTempMap.put( gbFieldId ,  avgTempVariable    ) ;
                    aggrResultMap.put( gbFieldId ,  avgTempVariable.getFieldValue()/avgTempVariable.getTimes() ) ;
                }
            }

//        }

        System.out.println( "-------------------------------------------------------" );
        if(  what.equals(Op.AVG) ){
            System.out.println( "avg int merge =====" + tup + "===" +  aggrResultMap + "===" + avgTempMap );
        }else{
            System.out.println( "int merge =====" + tup + "===" +  aggrResultMap  );
        }

    }



    /**
     * Create a DbIterator over group aggregate results.
     *
     * @return a DbIterator whose tuples are the pair (groupVal,
     *   aggregateVal) if using group, or a single (aggregateVal) if no
     *   grouping. The aggregateVal is determined by the type of
     *   aggregate specified in the constructor.
     */
    public DbIterator iterator() {

        if( gbfield == -1) {
            return new IntNoGroupIterator( aggrResultMap  , Utility.getTupleDesc(1)  ) ;
        }

        return new IntGroupIterator( aggrResultMap  , tupleDesc  ) ;
        // some code goes here
//        throw new UnsupportedOperationException("implement me");
    }


}
